package com.study.tomcat.nio;

import com.study.tomcat.nio.http.MyNioRequest;
import com.study.tomcat.nio.http.MyNioResponse;
import com.study.tomcat.nio.http.MyNioServlet;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;

import java.io.FileInputStream;
import java.net.ServerSocket;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @Author: huang
 * @Description 启动方法
 * @Date: 2021-01-16 13:07
 */
public class MyTomcatNio {

    private final int port = 8080;

    private ServerSocket server;

    private Properties properties = new Properties();

    private Map<String, MyNioServlet> servletMap = new HashMap<>();

    public static void main(String[] args) {
        new MyTomcatNio().start();
    }

    private void start() {
        init();

        EventLoopGroup bossGroup = new NioEventLoopGroup();

        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap server = new ServerBootstrap();

        try {
            server.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(Channel client) throws Exception {
                            client.pipeline().addLast(new HttpResponseEncoder());
                            client.pipeline().addLast(new HttpRequestDecoder());
                            client.pipeline().addLast(new MyTomcatHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE,true);

            ChannelFuture f = server.bind(this.port).sync();
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private void init() {
        try {
            String web_info = this.getClass().getResource("/").getPath();
            FileInputStream fileInputStream = new FileInputStream(web_info + "web-nio.properties");

            properties.load(fileInputStream);

            for (Object k : properties.keySet()) {
                String key = k.toString();
                if (key.endsWith(".url")) {
                    String servletName = key.replaceAll("\\.url$", "");
                    String url = properties.getProperty(key);
                    String className = properties.getProperty(servletName + ".className");
                    MyNioServlet servlet = (MyNioServlet) Class.forName(className).newInstance();
                    servletMap.put(url, servlet);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private class MyTomcatHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if(msg instanceof HttpRequest){
                HttpRequest req = (HttpRequest) msg;

                MyNioRequest request = new MyNioRequest(ctx,req);
                MyNioResponse response = new MyNioResponse(ctx,req);

                String url = request.getUrl();

                if(servletMap.containsKey(url)){
                    servletMap.get(url).service(request,response);
                }else {
                    response.write("404 - Not Found!");
                }
            }
        }
    }
}
